package org.loong.crypto.model.asn1.sm2;

import java.util.Enumeration;

import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;

/**
 * SM2 cipher.
 * 
 * <pre>
 * SM2Cipher ::== SEQUENCE{
 *     XCoordinate          INTEGER,
 *     YCoordinate          INTEGER,
 *     HASH                 OCTET STRING SIZE(32),
 *     CipherText           OCTET STRING
 * }
 * </pre>
 */
public class SM2Cipher extends ASN1Object {

    private ASN1Integer x;

    private ASN1Integer y;

    private ASN1OctetString hash;

    private ASN1OctetString cipherText;

    public SM2Cipher(byte[] x, byte[] y, byte[] hash, byte[] cipherText) {
        this(new ASN1Integer(x), new ASN1Integer(y), new DEROctetString(hash), new DEROctetString(cipherText));
    }

    public SM2Cipher(ASN1Integer x, ASN1Integer y, ASN1OctetString hash, ASN1OctetString cipherText) {
        this.x = x;
        this.y = y;
        this.hash = hash;
        this.cipherText = cipherText;
    }

    public SM2Cipher(ASN1Sequence seq) {
        if (seq.size() != 4) {
            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
        }

        Enumeration<?> e = seq.getObjects();
        this.x = ASN1Integer.getInstance(e.nextElement());
        this.y = ASN1Integer.getInstance(e.nextElement());
        this.hash = ASN1OctetString.getInstance(e.nextElement());
        this.cipherText = ASN1OctetString.getInstance(e.nextElement());
    }

    public static SM2Cipher getInstance(Object obj) {
        if (obj instanceof SM2Cipher) {
            return (SM2Cipher) obj;
        }

        if (obj != null) {
            return new SM2Cipher(ASN1Sequence.getInstance(obj));
        }

        return null;
    }

    public ASN1Integer getX() {
        return x;
    }

    public ASN1Integer getY() {
        return y;
    }

    public ASN1OctetString getHash() {
        return hash;
    }

    public ASN1OctetString getCipherText() {
        return cipherText;
    }

    @Override
    public ASN1Primitive toASN1Primitive() {
        ASN1EncodableVector v = new ASN1EncodableVector(4);
        v.add(x);
        v.add(y);
        v.add(hash);
        v.add(cipherText);
        return new DERSequence(v);
    }
}
